// Virtio 设备定义
// 参考 xv6-riscv 实现

#ifndef __VIRTIO_H__
#define __VIRTIO_H__

#include "types.h"
#include "memlayout.h"

// virtio mmio 寄存器地址
#define VIRTIO0 0x10008000L

// virtio mmio 寄存器偏移
#define VIRTIO_MAGIC         0x000
#define VIRTIO_VERSION       0x004
#define VIRTIO_DEVICE_ID     0x008
#define VIRTIO_VENDOR_ID     0x00c
#define VIRTIO_DEVICE_FEATURES 0x010
#define VIRTIO_DEVICE_FEATURES_SEL 0x014
#define VIRTIO_DRIVER_FEATURES    0x020
#define VIRTIO_DRIVER_FEATURES_SEL 0x024
#define VIRTIO_QUEUE_SEL     0x030
#define VIRTIO_QUEUE_NUM_MAX 0x034
#define VIRTIO_QUEUE_NUM     0x038
#define VIRTIO_QUEUE_READY   0x044
#define VIRTIO_QUEUE_NOTIFY  0x050
#define VIRTIO_INTERRUPT_STATUS 0x060
#define VIRTIO_INTERRUPT_ACK    0x064
#define VIRTIO_STATUS        0x070
#define VIRTIO_QUEUE_DESC_LOW  0x080
#define VIRTIO_QUEUE_DESC_HIGH 0x084
#define VIRTIO_QUEUE_AVAIL_LOW 0x090
#define VIRTIO_QUEUE_AVAIL_HIGH 0x094
#define VIRTIO_QUEUE_USED_LOW  0x0a0
#define VIRTIO_QUEUE_USED_HIGH 0x0a4

#define VIRTIO_MAGIC_VALUE    0x74726976
#define VIRTIO_VERSION_LEGACY 0x1
#define VIRTIO_VERSION_MODERN 0x2
#define VIRTIO_DEVICE_ID_BLOCK 0x2
#define VIRTIO_STATUS_ACK     0x1
#define VIRTIO_STATUS_DRIVER  0x2
#define VIRTIO_STATUS_DRIVER_OK 0x4
#define VIRTIO_STATUS_FEATURES_OK 0x8

// virtio 队列描述符
#define VRING_DESC_F_NEXT    1
#define VRING_DESC_F_WRITE   2
#define VRING_DESC_F_INDIRECT 4

struct virtq_desc {
  uint64 addr;
  uint32 len;
  uint16 flags;
  uint16 next;
};

#define VRING_AVAIL_F_NO_INTERRUPT 1

struct virtq_avail {
  uint16 flags;
  uint16 idx;
  uint16 ring[];
};

struct virtq_used_elem {
  uint32 id;
  uint32 len;
};

struct virtq_used {
  uint16 flags;
  uint16 idx;
  struct virtq_used_elem ring[];
};

// virtio-blk 请求头
#define VIRTIO_BLK_T_IN           0
#define VIRTIO_BLK_T_OUT          1
#define VIRTIO_BLK_T_FLUSH        4
#define VIRTIO_BLK_T_DISCARD      11
#define VIRTIO_BLK_T_WRITE_ZEROES 13

#define VIRTIO_BLK_S_OK           0
#define VIRTIO_BLK_S_IOERR        1
#define VIRTIO_BLK_S_UNSUPP       2

// virtio-blk 请求头（不包含数据，数据在单独的缓冲区中）
struct virtio_blk_req {
  uint32 type;
  uint32 reserved;
  uint64 sector;
};

#define NUM 8  // 描述符数量

#endif // __VIRTIO_H__